package cn.witsky.rtp2ws;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;

import cn.witsky.rtp2ws.cache.CallManager;
import cn.witsky.rtp2ws.cache.ClientManager;
import cn.witsky.rtp2ws.cache.UdpServerManager;
import cn.witsky.rtp2ws.client.ws.ClientUtil;
import cn.witsky.rtp2ws.client.ws.UrlParam;
import cn.witsky.rtp2ws.domain.CallInfo;
import cn.witsky.rtp2ws.exception.StartUpException;
import cn.witsky.rtp2ws.push.disruptor.EventCacheManage;
import cn.witsky.rtp2ws.push.retry.RetryManager;
import cn.witsky.rtp2ws.push.threadpool.PushManager;
import cn.witsky.rtp2ws.util.HttpUtil;
import cn.witsky.rtp2ws.util.NetWorkUtil;
import cn.witsky.rtp2ws.util.RedisUtil;
import io.netty.util.internal.StringUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@SpringBootApplication
public class Rtp2WsApplication implements ApplicationRunner {
	private static Logger logger = LoggerFactory.getLogger(Rtp2WsApplication.class);
	@Autowired
	private Environment env;

	public static void main(String[] args) {
		if (args.length == 1 && args[0].equalsIgnoreCase("-v")) {
			cn.witsky.common.Version.showVersion();
			return;
		}
		SpringApplication app = new SpringApplication(Rtp2WsApplication.class);
		app.run(args);
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		logger.info("rtp2ws程序开始启动了......");
		String serverIdStr = getValue(args, "serverId");
		if (serverIdStr.equals("")) {
			throw new StartUpException("启动参数 serverId是空的！");
		} else {
			try {
				Server.setServerId(Integer.parseInt(serverIdStr));
			} catch (Exception ex) {
				throw new StartUpException("启动参数 serverId必须是数字！");
			}
		}
		String ip = getValue(args, "server.address");
		if (ip.equals("")) {
			throw new StartUpException("启动参数 server.address是空的！");
		} else {
			if (!NetWorkUtil.isValidIp(ip)) {
				throw new StartUpException("启动参数 server.address不是一个有效的ip地址！");
			}
		}
		String port = getValue(args, "server.port");
		if (port.equals("")) {
			throw new StartUpException("启动参数 server.port是空的！");
		}
		String registerUrl = getValue(args, "registerUrl");
		if (registerUrl.equals("")) {
			logger.warn("启动参数 registerUrl是空的！不向rpx注册........");
		}

		String wsProxyUrl = getValue(args, "wsProxyUrl");
		if (wsProxyUrl.equals("")) {
			logger.warn("启动参数 wsProxyUrl是空的,不走代理地址");
			Server.useProxy = false;
		}

		String wsUrl = getValue(args, "wsUrl");
		if (wsUrl.equals("")) {
			logger.warn("启动参数 wsUrl是空的,ws推送地址使用申请端口时的ws地址");
		}

		String minPortStr = getValue(args, "udpMinPort");
		if (minPortStr.equals("")) {
			throw new StartUpException("启动参数 minPort是空的！");
		}
		String maxPortStr = getValue(args, "udpMaxPort");
		if (maxPortStr.equals("")) {
			throw new StartUpException("启动参数 maxPort是空的！");
		}
		int minPort = Integer.parseInt(minPortStr);
		int maxPort = Integer.parseInt(maxPortStr);
		if (minPort > maxPort) {
			throw new StartUpException("启动参数 minPort比maxPort大！");
		} else {
			if ((maxPort - minPort) % 2 == 0) {
				maxPort = maxPort - 1;
			}
		}
		String reuseUdpPort= getValue(args, "reuseUdpPort");
		String sendWsSyncStr=getValue(args, "sendWsSync");
		Server.setReusePort(reuseUdpPort);
		Server.setSendWsSync(sendWsSyncStr);
		
		String ffmpegBinPath = getValue(args, "ffmpegBinPath");
		if (ffmpegBinPath.equals("")) {
			throw new StartUpException("启动参数 ffmpegBinPath是空的！");
		}
		Server.setFfmpegBinPath(ffmpegBinPath);
		
		String rtpSpeed = getValue(args, "rtpSpeed");
		if (rtpSpeed.equals("")) {
			throw new StartUpException("启动参数 rtpSpeed是空的！");
		}
		Server.setRtpSpeed(rtpSpeed);

		String rtpPayload = getValue(args, "rtpPayload");
		if (rtpPayload.equals("")) {
			throw new StartUpException("启动参数 rtpPayload是空的！");
		}

		Server.setPayLoad(rtpPayload);
		String appKey = getValue(args, "appKey");
		if (appKey.equals("")) {
			throw new StartUpException("启动参数 appKey是空的！");
		}
		Server.setAppKey(appKey);

		String appId = getValue(args, UrlParam.APP_ID);
		if (appId.equals("")) {
			throw new StartUpException("启动参数 appId是空的！");
		}
		String saveFileDaysStr=getValue(args,"saveFileDays");
		if(!StringUtil.isNullOrEmpty(saveFileDaysStr)) {
			int saveFileDays=Integer.parseInt(saveFileDaysStr);
			Server.setSaveFileDays(saveFileDays);
		}
		String saveFile = getValue(args,"saveFile");
		if (!StringUtil.isNullOrEmpty(saveFile)&&saveFile.equals("1")) {
			Server.setSaveFile(true);
		}else {
			Server.setSaveFile(false);
		}	
		String compress = getValue(args,"compress");
		if (!StringUtil.isNullOrEmpty(compress)&&compress.equals("1")) {
			Server.setCompress(true);
		}else {
			Server.setCompress(false);
		}		
		String signature=getValue(args,"signature");
		if(signature.equals("0")) {
			Server.setSignature(false);
		}
		Server.setAppId(appId);
		String addedInfo = getValue(args, UrlParam.ADDED_INFO);
		String heartbeatTimeStr = getValue(args, "wsProxyHeartbeatTime");
		Server.setAddedInfo(addedInfo);
		this.setWsProxyUrl(wsProxyUrl);
		ClientUtil.setTestUrl(wsUrl);
		ClientUtil.setHeartbeatTime(heartbeatTimeStr);
		Server.setIp(ip);
		Server.setPort(port);
		this.checkRedis();
		this.checkId();
		StringBuilder startLog = new StringBuilder("");
		startLog.append("\r\n");
		startLog.append("******启动参数列表*************\r\n");
		startLog.append("******").append("服务名:").append(Server.ServerName).append("\r\n");
		startLog.append("******").append("监听的Ip:").append(ip).append("\r\n");
		startLog.append("******").append("监听的端口:").append(port).append("\r\n");
		startLog.append("******").append("rpx负载注册地址:").append(registerUrl).append("\r\n");
		startLog.append("******").append("ws代理地址:").append(wsProxyUrl).append("\r\n");
		startLog.append("******").append("ws代理地址检测频率:").append(heartbeatTimeStr).append("\r\n");
		startLog.append("******").append("ws测试地址:").append(wsUrl).append("\r\n");
		if(Server.sendWsSync) {
			startLog.append("******").append("ws推送策略:").append("同步").append("\r\n");
		}else {
			startLog.append("******").append("ws推送策略:").append("异步").append("\r\n");
		}		
		startLog.append("******").append("接收rtp的Udp端口范围:").append(minPort).append("-").append(maxPort).append("\r\n");
		if(Server.reusePort) {
			startLog.append("******").append("端口使用策略:").append("复用端口").append("\r\n");
		}else {
			startLog.append("******").append("端口使用策略:").append("不复用端口").append("\r\n");
		}
		startLog.append("******").append("rtp流的速率:").append(rtpSpeed).append("\r\n");
		startLog.append("******").append("rtp流的payload:").append(rtpPayload).append("\r\n");
		if(Server.isSaveFile()) {
			startLog.append("******").append("是否存储Rtp流文件:").append("是").append("\r\n");
		}else {
			startLog.append("******").append("是否存储Rtp流文件:").append("否").append("\r\n");
		}
		if(Server.isCompress()) {
			startLog.append("******").append("是否开启Rtp流文件压缩:").append("是").append("\r\n");
		}else {
			startLog.append("******").append("是否开启Rtp流文件压缩:").append("否").append("\r\n");
		}
		if(Server.isSignature()) {
			startLog.append("******").append("是否开启接口鉴权:").append("是").append("\r\n");
		}else {
			startLog.append("******").append("是否开启接口鉴权:").append("否").append("\r\n");
		}	
		startLog.append("******").append("ffmpegBinPath:").append(ffmpegBinPath).append("\r\n");
		startLog.append("******").append("appKey:").append(appKey).append("\r\n");
		startLog.append("******").append(UrlParam.APP_ID + ":").append(appId).append("\r\n");
		startLog.append("******").append(UrlParam.ADDED_INFO + ":").append(addedInfo).append("\r\n");
		Server.setServerInfo(startLog.toString());

		boolean isSuccess = true;
		if (!registerUrl.equals("")) {
			this.register(registerUrl.split(","),ip,port);
		}

		if (isSuccess) {
			String ThreadCountStr = getValue(args, "ThreadCount");
			if (!StringUtil.isNullOrEmpty(ThreadCountStr)) {
				Server.THRED_COUNT = Integer.parseInt(ThreadCountStr);
			}
			if(!Server.sendWsSync) {
				EventCacheManage.initialize();
			}
			ClientManager.initialize();
			PushManager.initialize();
			RetryManager.initialize();
			this.loadCall();
			this.initUdpPort(minPort, maxPort);

		} else {
			throw new StartUpException("像nginx服务发起注册失败！");
		}
		logger.info(Server.getServerInfo());
		System.out.println(Server.getServerInfo());
		logger.info("rtp2ws启动成功了......");
	}

	private String getValue(ApplicationArguments args, String key) {
		if (env.containsProperty(key)) {
			return env.getProperty(key);
		} else {
			return "";
		}

	}

	// 检测redis是否可用
	public void checkRedis() throws StartUpException {
		RedisUtil.test();
	}

	// 检测ServerId是否合法
	public void checkId() throws StartUpException {
		if (RedisUtil.onLine() == -1) {
			throw new StartUpException("当前已经存在serverId是:" + Server.serverId + "的服务了");
		}
	}

	// 将ws代理地址设置到redis
	public void setWsProxyUrl(String wsProxyUrl) {
		if (!StringUtil.isNullOrEmpty(wsProxyUrl)) {
			ClientUtil.setProxyUrl(wsProxyUrl);
		}

	}

	// 加载已经绑定了端口的会话
	public void loadCall() {
		if(Server.reusePort) {
			Map<Object, Object> callList = RedisUtil.loadCall();
			for (Object key : callList.keySet()) {		
				String val=callList.get(key).toString();
				JSONObject callJson = JSONObject.fromObject(val);
				CallInfo call=CallManager.createCallInfo(callJson);
				logger.info("加载数据 call:{}",call);
				if (call != null) {
					UdpServerManager.bindPort(call);
					call.bindSrcPort();
				}
			}			
		}else {
			Map<Object, Object> binds = RedisUtil.loadBind();
			for (Object obj : binds.keySet()) {
				String callId = obj.toString();
				CallInfo call = RedisUtil.getCallInfo(callId);
				if (call != null) {
					logger.info("加载数据 call:{}",call);
					call.setUdpPort(Integer.parseInt(binds.get(callId).toString()));
					UdpServerManager.bindPort(call);
					call.bindSrcPort();
				} else {
					int result=RedisUtil.freeUdpPort(callId);
					if(result<0) {
						logger.error("释放call:"+callId+"的端口失败了");
					}
				}

			}
		}

	}

	// 初始化未被占用的端口
	public void initUdpPort(int minPort, int maxPort) {
		UdpServerManager.init(minPort, maxPort);
	}

	// 向nginx发起注册
	public boolean register(String[] hosts,String ip,String port) {
		boolean isSuccess = false;
		int i = 0;
		for (String host : hosts) {
			String url = "http://" + host + "/createRouteURL";
			JSONObject servers = new JSONObject();
			JSONArray list = new JSONArray();
			JSONObject server = new JSONObject();
			servers.put("key", Server.serverType);
			server.put("id", Server.serverId);
			server.put("ip",ip);
			server.put("port",port);
			server.put("weight", 1);
			list.add(server);
			servers.put("value", list);
			JSONObject jsonParam = new JSONObject();
			JSONArray data = new JSONArray();
			data.add(servers);
			jsonParam.put("data", data);
			logger.info("jsonParam:{}", jsonParam);
			JSONObject result = HttpUtil.doPost(url, jsonParam);
			if (result != null) {
				if (result.getString("code").equals("0")) {
					logger.debug("第{}次发起注册成功了。。。。。。", i);
					isSuccess = true;
					break;
				} else {
					logger.warn("第{}次发起注册失败了。。。。。。", i);
				}
			}
		}
		return isSuccess;
	}

}
